home *** CD-ROM | disk | FTP | other *** search
- PAGE 60,128
- TITLE Asynchronous Print Program - SPOOLER.ASM V1.0
- PAGE
- COMMENT *
-
- PROGRAM: SPOOLER.ASM Version 1.0
- AUTHOR: Valdis Skuja
- DATE: September 15,1982
-
-
- MODULE DESCRIPTION
- ------------------
-
- This program sets up an environment in which
- any output for the printer is buffered before being
- printed. After the output is placed into the buffer
- control is passed back to the caller. The output is
- then printed asynchronously. The asynchronous print
- routine is given control at each tick of the system
- timer, at which time it keeps sending the buffered
- print output to the printer until the printer is
- busy.
- Using this method the program printing does
- not have to wait for the printed output to complete
- before continuing, therefore making better use of
- the CPU and allows the user to run other programs as
- the printer is still printing.
- The buffer size is set in the program as 16K, but
- this can be changed by changing the values in the
- define statements for "BUFSIZE" and "BUFFER_AREA" and
- then reassembling and relinking the program.
- To invoke this program it must be assembled and
- linked as SPOOLER.EXE then while in DOS issue the
- command SPOOLER. When invoked the program will remain
- resident and can only be removed by re-booting DOS.
- Do not invoke the program more than once without
- re-booting as it will grab an additional 16K of your
- RAM each time it is called.
- Anyone having any questions or problems about
- using this program can contact me at 223-2528, and
- I will try to help you if I can.
-
- Valdis Skuja.
-
- *
- BIOS_DATA SEGMENT AT 40H
- ORG 8H
- PRINTER_BASE DW 4 DUP(?)
- ORG 3FH
- MOTOR_STATUS DB ?
- MOTOR_COUNT DB ?
- ORG 6CH
- TIMER_LOW DW ?
- TIMER_HIGH DW ?
- TIMER_OFL DB ?
- BIOS_DATA ENDS
- STACK SEGMENT PARA STACK 'STACK'
- DB 10 DUP('STACK ')
- STACK ENDS
- CSEG SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CSEG,DS:BIOS_DATA,ES:CSEG,SS:STACK
- INIT_ROUTINE PROC FAR
- JMP START ;BR. AROUND BUFFER
- FLAGS DB 0 ;FLAGS BYTE
- BF_FULL EQU 80H ;BUFFER FULL
- BF_EMPTY EQU 40H ;BUFFER EMPTY
- IO_ACTIVE EQU 20H ;IO CURRENTLY ACTIVE
- SOFTWARE_INT EQU 10H ;SOFTWARE INTERRUPT
- NOT_FULL EQU 7FH ;BUFFER NOT FULL
- NOT_EMPTY EQU 0BFH ;BUFFER NOT EMPTY
- IO_NOT_ACTIVE EQU 0DFH ;NO IO ACTIVE
- NOT_SOFTWARE EQU 0EFH ;NOT SOFTWARE INT.
- ;
- INTA00 EQU 20H
- INTA01 EQU 21H
- EOI EQU 20H ;END OF INTERUPT
- ;
- BUFSIZE DW 16384 ;BUFFER SIZE
- PRINTER_@ DW 0 ;PRINTER ADDRESS
- FIRST_CHAR DW 0 ;FIRST CHAR. POINTER
- LAST_CHAR DW 0 ;LAST CHAR. POINTER
- BUFFER_AREA DB 16384 DUP(?) ;BUFFER AREA 24K
- END_OF_BUF EQU $ ;END OF BUFFER
- START:
- PUSH AX ;SAVE AX CONTENTS
- PUSH DS ;SAVE DS CONTENTS
- OR FLAGS,BF_EMPTY ;SET BUFFER EMPTY
- MOV DX,OFFSET PRINTER_INT ;GET PRINTER INT. RTN.
- MOV AX,CS ;GET SEG PTR.
- MOV DS,AX ;SET INT "40" CSEG
- MOV AH,25H ;DOS CALL - SET INT.
- MOV AL,40H ;INDICATE INT. "40"
- INT 21H ;CALL DOS
- MOV DX,OFFSET PRINT_IO ;GET PRINT IO RTN.
- MOV AX,CS ;GET SEG PTR.
- MOV DS,AX ;SET INT "17" CSEG
- MOV AH,25H ;DOS CALL - SET INT.
- MOV AL,17H ;REPLACE INT "17"
- INT 21H ;CALL DOS
- MOV DX,OFFSET TIMER_INT ;GET TIMER_INT TRN
- MOV AX,CS ;GET SEG PTR.
- MOV DS,AX ;SET INT "8" CSEG
- MOV AH,25H ;DOS CALL - SET INT.
- MOV AL,08H ;REPLACE INT "8"
- INT 21H ;CALL DOS
- PUSH DS ;SAVE DS
- PUSH DX ;SAVE DX
- MOV DX,BIOS_DATA
- MOV DS,DX
- MOV DX,PRINTER_BASE ;@ OF 1ST PRINTER
- MOV PRINTER_@,DX ;SAVE PRINTER @
- ADD DX,2 ;POINT TO OUTPUT PORT
- MOV AL,8 ;SET INIT LINE LOW
- OUT DX,AL
- MOV AX,1000
- INIT_LOOP:
- DEC AX ;LOOP FOR RESET TO TAKE
- JNZ INIT_LOOP ;INIT_LOOP
- MOV AL,0CH ;INT. OFF TO START
- OUT DX,AL
- MOV DX,OFFSET BUFFER_AREA ;LOCATE BUFFER AREA
- MOV FIRST_CHAR,DX ;AND SET UP THE FIRST
- MOV LAST_CHAR,DX ;AND LAST CHAR POINTERS
- POP DX ;RESTORE DX
- POP DS ;RESTORE DS
- PUSH ES ;PUSH PGM PREFIX @
- MOV AX,CS ;CURRENT CSEG
- PUSH CX ;SAVE CX
- MOV CX,ES ;@ OF PGM PREFIX
- SUB AX,CX ;OFFSET FROM PGM. PRFX.
- MOV CL,4
- SHL AX,CL ;MULT. BY 16
- MOV DX,AX ;SAVE FOR LATER
- POP CX ;RESTORE CX
- ADD AX,OFFSET NEXT_INSTR ;CALC NEXT INSTR OFFSET
- PUSH AX ;SAVE NEXT INST OFFSET
- RET ;GOTO NEXT INSTR.76
- NEXT_INSTR:
- POP DS ;RESTORE DS
- POP AX ;RESTORE AX
- ADD DX,OFFSET PGM_END ;LOCATE END OF PGM.
- INT 27H ;END BUT STAY RESIDENT
- INIT_ROUTINE ENDP
- ;
- ;
- PRINTER_INT PROC NEAR
- ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:STACK
- PUSH SI ;SAVE SI
- PUSH DS ;SAVE DS
- PUSH ES ;SAVE ES
- PUSH AX ;SAVE AX
- PUSH BX ;SAVE BX
- PUSH CX ;SAVE CX
- PUSH DX ;SAVE DX
- MOV SI,CSEG
- MOV DS,SI ;SET UP DS
- MOV ES,SI ;SET UP ES
- NEXT_CHAR:
- TEST FLAGS,BF_EMPTY ;BUFFER EMPTY?
- JZ CHECK_FOR_EMPTY ;B.I.N
- JMP PRINTER_INT_RET ;RETURN FROM INTERRUPT
- CHECK_FOR_EMPTY:
- MOV SI,FIRST_CHAR ;OFFSET TO PRINT CHAR
- CMP SI,LAST_CHAR ;IS THIS LAST CHAR.
- JNE NOT_LAST_CHAR ;B.I.N
- OR FLAGS,BF_EMPTY ;SET BUFFER EMPTY
- NOT_LAST_CHAR:
- CLD ;CLEAR DIRECTION FLAG
- ; TO INCREMENT SI
- LODSB ;GET CHAR IN AL
- CMP SI,OFFSET END_OF_BUF ;END OF BUFFER?
- JNE PRINT_THE_CHAR ;NO, BRANCH
- MOV SI,OFFSET BUFFER_AREA ;BEGINNING OF BUFFER
- PRINT_THE_CHAR:
- MOV DX,PRINTER_@ ;GET PRINTER ADDR.
- MOV CX,100 ;SET BUSY LOOP COUNTER
- OUT DX,AL ;PRINT THE CHAR.
- INC DX ;POINT TO STATUS PORT
- WAIT_NOT_BUSY:
- IN AL,DX ;GET PRINTER STATUS
- TEST AL,80H ;STILL BUSY?
- JNZ OUT_STROBE ;OUT STROBE
- LOOP WAIT_NOT_BUSY ;KEEP TRYING
- AND FLAGS,NOT_EMPTY ;STILL BUSY-SET NOT EMPTY
- JMP PRINTER_INT_RET ;AND RETURN W/O PRINTING
- OUT_STROBE:
- MOV AL,1DH ;STROBE HIGH
- INC DX ;POINT TO OUTPUT PORT
- OUT DX,AL
- MOV AL,1CH ;STROBE LOW
- OUT DX,AL
- MOV FIRST_CHAR,SI ;SET NEXT CHAR TO PRINT
- AND FLAGS,NOT_FULL ;SET BUFFER NOT FULL
- JMP NEXT_CHAR ;PRINT NEXT CHAR
- PRINTER_INT_RET:
- POP DX ;RESTORE DX
- POP CX ;RESTORE CX
- POP BX ;RESTORE BX
- POP AX ;RESTORE AX
- POP ES ;RESTORE ES
- POP DS ;RESTORE DS
- POP SI ;RESTORE SI
- IRET
- PRINTER_INT ENDP
- ;
- ;
- PRINT_IO PROC NEAR
- ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:STACK
- PUSH DI ;SAVE DI
- PUSH DS ;SAVE DS
- PUSH ES ;SAVE ES
- PUSH BX ;SAVE BX
- MOV DI,CSEG
- MOV ES,DI ;SET UP ES
- MOV DS,DI ;SET UP DS
- OR AH,AH ;PRINT FUNCTION?
- JNZ PRINT_IO_RET ;NO, RETURN
- TEST FLAGS,BF_EMPTY ;BUFFER EMPTY?
- JZ SAVE_NEXT_CHAR ;B.I.N
- MOV DI,FIRST_CHAR ;GET PTR. TO 1ST CHAR
- MOV LAST_CHAR,DI ;LAST CHAR = 1ST CHAR
- STOSB ;MOVE CHAR TO BUFFER
- AND FLAGS,NOT_EMPTY ;IND. BUFFER NOT EMPTY
- JMP PRINT_IO_RET ;RETURN TO CALLER
- SAVE_NEXT_CHAR:
- MOV BX,LAST_CHAR ;GET LAST CHAR. PTR.
- INC BX ;POINT TO NEXT CHAR.
- CMP BX,OFFSET END_OF_BUF ;END OF BUFFER?
- JNE CHECK_FOR_FULL ;B.I.N
- MOV BX,OFFSET BUFFER_AREA ;BEGINNING OF BUFFER
- CHECK_FOR_FULL:
- CMP BX,FIRST_CHAR ;LAST_CHAR = FIRST_CHAR
- JNE SAVE_CHAR ;B.I.N
- OR FLAGS,BF_FULL ;SET BUFFER FULL
- STI ;START INTERRUPTS
- FULL_LOOP:
- TEST FLAGS,BF_FULL ;FULL BUFFER?
- JNZ FULL_LOOP ;LOOP IF FULL
- CLI ;STOP INTERRUPTS
- JMP SAVE_NEXT_CHAR ;TRY AGAIN
- SAVE_CHAR:
- MOV LAST_CHAR,BX ;UPDATE LAST_CHAR
- MOV DI,BX
- STOSB
- AND FLAGS,NOT_EMPTY ;IND. BUFFER NOT EMPTY
- PRINT_IO_RET:
- POP BX ;RESTORE BX
- POP ES ;RESTORE ES
- POP DS ;RESTORE DS
- POP DI ;RESTORE DI
- SUB AH,AH ;CLEAR RETURN CODE
- IRET
- PRINT_IO ENDP
- TIMER_INT PROC NEAR
- ASSUME CS:CSEG,DS:BIOS_DATA
- STI ;INTERRUPTS BACK ON
- PUSH DS
- PUSH AX
- PUSH DX ;SAVE MACHINE STATE
- MOV AX,BIOS_DATA
- MOV DS,AX ;ESTABLISH ADDRESSABILITY
- INC TIMER_LOW ;INCREMENT TIME
- JNZ T4 ;TEST_DAY
- INC TIMER_HIGH ;INCREMENT HIGH WORD OF TIME
- T4: ;TEST_DAY
- CMP TIMER_HIGH,018H ;TEST FOR COUNT EQUALLING 24 HOURS
- JNZ T5 ;DISKETTE_CTL
- CMP TIMER_LOW,0B0H
- JNZ T5 ;DISKETTE_CTL
- ;------ TIMER HAS GONE 24 HOURS
- MOV TIMER_HIGH,0
- MOV TIMER_LOW,0
- MOV TIMER_OFL,1
- T5: ;DISKETTE_CTL
- DEC MOTOR_COUNT
- JNZ T6 ;RETURN IF COUNT NOT OUT
- AND MOTOR_STATUS,0F0H ;TURN OFF MOTOR RUNNING BITS
- MOV AL,0CH
- MOV DX,03F2H ;FDC CTL PORT
- OUT DX,AL ;TURN OFF THE MOTOR
- T6: ;TIMER_RET
- INT 1CH ;TRANSFER CONTROL TO USER ROUTINE
- INT 40H ;TRANSFER CNTL TO ASYNC. PRINTER RTN.
- MOV AL,EOI
- OUT 020H,AL ;END OF INTERRUPT TO 8259
- POP DX
- POP AX
- POP DS ;RESET MACHINE STATE
- IRET ;RETURN FROM INTERRUPT
- TIMER_INT ENDP
- PGM_END: DB 0
- CSEG ENDS ;END OF CODE SEG.
- END INIT_ROUTINE